package org.ipp4j.core;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

import org.ipp4j.core.standard.Tag;
import org.ipp4j.core.standard.Version;

/**
 * <p>
 * Standard IPP Messages.
 * 
 * @author cko
 * 
 */
public abstract class IppMessage {

	private Version version;
	private int requestId;

	private InputStream dataStream;

	private Map<AttributeGroup, Collection<Attribute>> attributeGroups = new LinkedHashMap<AttributeGroup, Collection<Attribute>>();

	public IppMessage(Version version, int requestId) {
		super();
		this.version = version;
		this.requestId = requestId;
	}

	public Version getVersion() {
		return version;
	}

	public int getRequestId() {
		return requestId;
	}

	public Map<AttributeGroup, Collection<Attribute>> getAttributeGroups() {
		return attributeGroups;
	}

	public void addAttribute(AttributeGroup group, Attribute attribute) {
		Collection<Attribute> attributes = createIfEmpty(group);
		Attribute targetAttribute = null;
		for (Attribute lookupAttribute : attributes) {
			if (lookupAttribute.getValueTag().equals(attribute.getValueTag())) {
				targetAttribute = lookupAttribute;
			}
		}
		if (targetAttribute != null) {
			targetAttribute.updateValue(attribute.getName(),
					attribute.getValue());
		} else {
			attributes.add(attribute);
		}
	}

	public void updateAttribute(AttributeGroup group, Attribute attribute) {
		Collection<Attribute> attributes = createIfEmpty(group);
		Attribute targetAttribute = null;
		for (Attribute lookupAttribute : attributes) {
			if (lookupAttribute.getValueTag().equals(attribute.getValueTag())) {
				targetAttribute = lookupAttribute;
			}
		}
		if (targetAttribute != null) {
			targetAttribute.updateValue(attribute.getName(),
					attribute.getValue());
		} else {
			attributes.add(attribute);
		}
	}

	public void updateAttribute(Attribute attribute) {
		for (Collection<Attribute> attributes : attributeGroups.values()) {
			for (Attribute lookupAttribute : attributes) {
				if (lookupAttribute.getValueTag().equals(
						attribute.getValueTag())) {
					lookupAttribute.updateValue(attribute.getName(),
							attribute.getValue());
					break;
				}
			}

		}
	}

	/**
	 * <p>
	 * Search for a attribute with given valueTag.
	 * 
	 * @param valueTag
	 * @return if no match found, null is return.
	 */
	public Attribute getAttribute(Tag valueTag) {
		for (Collection<Attribute> attributeList : attributeGroups.values()) {
			for (Attribute attribute : attributeList) {
				if (valueTag.equals(attribute.getValueTag())) {
					return attribute;
				}
			}
		}
		return null;
	}

	private Collection<Attribute> createIfEmpty(AttributeGroup group) {
		if (!attributeGroups.containsKey(group)) {
			attributeGroups.put(group, new ArrayList<Attribute>());
		}
		return attributeGroups.get(group);
	}

	@Override
	public String toString() {
		return "IppMessage [version=" + version + ", requestId=" + requestId
				+ ", attributeGroups=" + attributeGroups + "]";
	}

	public InputStream getDataStream() {
		return dataStream;
	}

	public void setDataStream(InputStream dataStream) {
		this.dataStream = dataStream;
	}

}
